LAMP之Apache的初始配置

这篇学习笔记,是工作中经常用到的Apache的基本配置,一定要熟练掌握。


1. 默认虚拟主机

1.1. 虚拟主机和默认虚拟主机

首先我们要了解一下虚拟主机的概念。早期的Linux服务器上,一个服务器只能运行一个网站。但随着技术的发展,一个服务器上可以跑多个网站了,这样可以帮助我们节省成本。其实,这里的服务器就叫做主机,早期一个主机对应一个站点。而现在,一个主机可以跑多个站点,所以就有了虚拟主机的概念。

既然服务器上可以有多个虚拟主机,每个虚拟主机都会定义一个域名(当然也可以定义多个),只要把这个域名解析指向到该台服务器,我们自然就可以访问这个站点了。域名解析服务器IP地址,是由DNS服务器来完成的。

加入你访问的域名指向了你的服务器,而你又在这台服务器上配置标记了这个域名,这样这个域名就能够被正常访问。但是如果没有标记的域名也指向了这台服务器,那会有什么情况发生呢?这就又有了默认虚拟主机的概念产生。

httpd有一个特点,它首先是支持多个虚拟主机的,也就是可以在一个服务器上运行多个站点,标记多个域名。有标记的域名指向这台服务器,就会由对应的虚拟主机来处理。任何一个其它的没有标记的域名指向这台服务器,即只要没有对应的虚拟主机,就会由默认虚拟主机来处理。

那么这个默认虚拟主机该如何配置呢?下面就是配置它的方法。

1.2. 虚拟主机的配置

httpd的主配置文件是http.conf。我们先来在主配置文件中找到虚拟主机的配置语句,并开启这个功能,如下:

1
2
3
4
5
6
7
# vim /usr/local/apache2.4/conf/httpd.conf
#<==搜索关键字 httpd-vhost
...
# Virtual hosts
Include conf/extra/httpd-vhosts.conf
...
#<==找到上面这行把行首的井号删除,后面的绝对路径文件名即是虚拟主机的配置文件。保存退出

在httpd的主配置文件httpd.conf中开启了虚拟主机的功能之后,再来编辑虚拟主机配置文件/usr/local/apache2.4/conf/extra/httpd-vhosts.conf,后面的操作都是在这个文件里面完成的。

打开虚拟主机的配置文件,可以先看看该文件最后面两端(以<VirtualHost *:80>开头,以</VirtualHost>结尾),这样一段就是一个虚拟主机,在这里面可以定义网站的域名和对应的网站程序所在目录。而默认虚拟主机就是第一个配置段。做实验:把该配置文件里面的两端<VirtualHost>重新编辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<VirtualHost *:80>
ServerAdmin admin@localhost.com
DocumentRoot "/data/wwwroot/aming.com"
ServerName aming.com
ServerAlias www.aming.com
ErrorLog "logs/aming.com-error_log"
CustomLog "logs/aming.com-access_log" common
</VirtualHost>
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
</VirtualHost>

上述配置说明:

  • ServerAdmin指定管理员邮箱,这个没有什么实质作用,平时不用它。
  • DocumentRoot为该虚拟主机站点的根目录,网站的程序就放在这个目录下面。
  • ServerName为网站的域名,在这后面只能写一个域名。
  • ServerAlias为网站的第二域名,在这后面可以写多个域名,用空格分隔。
  • ErrorLog为站点的错误日志。
  • CustomLog为站点的访问日志,在工作中这个访问日志用得很多,需要关注一下。

假如在虚拟主机配置文件中,我们只定义了两个站点:aming.com和123.com,那么当把第三个域名abc.com指向本机的时候,当在浏览器访问abc.com时,会去访问aming.com(因为它是第一段定义的,所以是默认虚拟主机)。不妨来做个实验:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# mkdir -p /data/wwwroot/aming.com /data/wwwroot/www.123.com
[root@localhost ~]# echo "aming.com" > /data/wwwroot/aming.com/index.html
[root@localhost ~]# echo "123.com" > /data/wwwroot/www.123.com/index.html
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK #<==检查httpd配置是否正确
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
httpd not running, trying to start #<==热重启httpd服务,即不停止服务重新加载配置文件
[root@localhost ~]# curl -x127.0.0.1:80 aming.com
aming.com
[root@localhost ~]# curl -x127.0.0.1:80 www.123.com
123.com
[root@localhost ~]# curl -x127.0.0.1:80 www.abc.com
aming.com

由上例可以看出,默认虚拟主机为aming.com,不过把什么域名指向该服务器,只要配置文件中没有标记,就会访问这个默认虚拟主机。


2. 用户认证

2.1. 对整站做用户认证

这个功能就是在用户访问网站的时候,需要输入用户名和密码才能顺利访问。一些比较重要的站点或者网站后台通常会加上用户认证,目的是保证安全。

先来对123.com站点做一个全站的用户认证:把123.com那个虚拟主机编辑成如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~]# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
...
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
<Directory /data/wwwroot/www.123.com>
AllowOverride AuthConfig
AuthName "123.com user auth"
AuthType Basic
AuthUserFile /data/.htpasswd
require valid-user
</Directory>
</VirtualHost>
...

以上配置文件中的说明:

  • <Directory /data/wwwroot/www.123.com> 指定认证的目录
  • AllowOverride AuthConfig 这个相当于打开认证的开关
  • AuthName "123.com user auth" 自定义认证的名字,作用不大
  • AuthType Basic 认证的类型,一般为Basic,其它类型几乎不用
  • AuthUserFile /data/.htpasswd 指定密码文件所在位置
  • require valid-user 指定需要认证的用户为全部可用用户
  • </Directory> 结束标识

这样httpd的配置文件就配置完成了,但还需要创建密码文件,操作步骤如下:

1
2
3
4
5
6
7
[root@localhost ~]# /usr/local/apache2.4/bin/htpasswd -cm /data/.htpasswd aming
New password:
Re-type new password:
Adding password for user aming
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK #<==验证没有问题后才能重启或者重新加载
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful

上述配置文件中的说明:

  • htpasswd命令为创建用户的工具,-c为create(创建),-m指定密码加密方式为MD5。
  • /data/.htpasswd为密码文件,aming为要创建的用户。
  • 第一次执行该命令需要加-c,第二次再创建新的用户时,就不用加-c了,否则/data/.htpasswd文件会被重置,之前的用户被清空。

配置完成后,用浏览器访问一下www.123.com,不过得提前在真实机上面更改一下hosts文件,把www.123.com域名指向这台Linux机器,这样才能通过浏览器访问成功。

若是访问成功了,就会出现一个认证的提示框,需要输入用户名和密码。输入正确的用户名和密码后,才能进入到www.123.com的网站。

2.2. 针对某个目录或文件做用户认证

当然也可以针对某个目录或文件做用户认证,比如要对www.123.com/admin/目录进行认证,只需要修改一个地方,把<Directory /data/wwwroot/www.123.com> 改为 <Directory /data/wwwroot/www.123.com/admin/>。如果是一个文件,比如www.123.com/admin.php,则需要这样做:

1
2
3
4
5
6
7
8
9
10
11
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
<FilesMatch admin.php> #<==修改这里
AllowOverride AuthConfig
AuthName "123.com user auth"
AuthType Basic
AuthUserFile /data/.htpasswd
require valid-user
</FilesMatch> #<==以及修改这里
</VirtualHost>

但是这样修改后会有一个问题,网址中带有admin.php的链接都会弹出认证窗口。


3. 配置域名301跳转

这个用法比较普遍,一个网站可能会有多个域名,但是输入指向的一个网站的多个域名可能会发现,浏览器里的网址总是会变成一个固定的域名,这其实就是域名的跳转功能。

做域名跳转有什么用呢?主要是有两方面的作用:

  1. 一个站点有多个域名会对SEO有影响,说白了就是百度搜索关键词的排名有影响,如果把多个域名全部跳转到指定的一个域名,这样以这个域名为中心,就可以把权重集中在这个域名上,所以搜索关键词的排名也就靠前了。
  2. 如果之前的某个域名不再使用了,但是搜索引擎还留着之前老域名的链接,这意味着用户可能会搜到我们的网站并且点击老的域名,因此需要把老域名做个跳转,跳到新域名,这样用户搜的时候,也可以访问到网站。

下面来做实验实现这样一个需求,把123.com域名跳转到www.123.com,配置如下:

1
2
3
4
5
6
7
8
9
10
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^123.com$
RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L]
</IfModule>
</VirtualHost>

上述配置文件的说明:

  • <IfModule mod_rewrite.c> 要实现跳转功能需要mod_rewrite模块支持。
  • RewriteEngine on 打开rewrite功能
  • RewriteCond %{HTTP_HOST} !^www.123.com$ 定义rewrite的条件,当主机名(域名)是123.com的时候满足条件。
  • RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L] 定义rewrite的规则,当满足上面的条件时,这条规则才会执行。这里是有正则表达式存在的。RewriteRule后面由空格分成三个部分,第一部分为当前的URL,不过这个URL是不把主机头(也就是域名)算在内的;第二部分为要跳转的目标地址,这个地址可以写全(包含了主机头),当然也可以不加主机头,默认就是前面定义的ServerName;第三部分为一些选项,需要用方括号括起来,301为状态码,它称作”永久重定向”(还有一种跳转码为302,叫做”临时重定向”),L表示”last”,意思是跳转一次就结束了。

要实现域名跳转,需要有rewrite模块支持,所以先查看httpd是否已经加载该模块,如果没有还需要配置:

1
2
3
4
5
6
7
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -M | grep -i rewrite
#<==没有任何输出,则需要编辑httpd的主配置文件
[root@localhost ~]# vim /usr/local/apache2.4/conf/httpd.conf
#<==搜索rewrite,找到那行把前面的井号去掉
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -M | grep -i rewrite
rewrite_module (shared) #<==有这一行输出说明正常加载rewrite模块

配置完后,进行测试,可以用curl测试也可以看到效果,如下:

1
2
3
4
5
6
[root@localhost ~]# curl -x127.0.0.1:80 -I 123.com
HTTP/1.1 301 Moved Permanently
Date: Wed, 07 Mar 2018 18:28:47 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Location: http://www.123.com/
Content-Type: text/html; charset=iso-8859-1

可以看到状态码为301,跳转后的网站(Location那行)为http://www.123.com。

如果是多个域名,应该这样配置:

1
2
3
4
5
6
7
8
9
10
11
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^123.com$ [OR]
RewriteCond %{HTTP_HOST} ^456.com$
RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L]
</IfModule>
</VirtualHost>

或者

1
2
3
4
5
6
7
8
9
10
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www/123.com$
RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L]
</IfModule>
</VirtualHost>


4. 配置访问日志

这一节包含了两个内容,一个是Apache日志切割,另一个是不记录指定文件类型日志。

访问日志的作用很大,不仅可以记录网站的访问情况,还可以在网站有异常发生时帮助我们定位问题,比如当有攻击时,是可以通过查看日志看到一些规律的。要配置httpd访问日志,首先要在主配置文件中定义日志的格式,打开主配置文件:

1
2
3
[root@localhost ~]# vim /usr/local/apache2.4/conf/httpd.conf #<==搜索LogFormat
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common

说明:

  • 可以阿奎那到有两个格式的日志,建议使用第一个,记录的信息会更全。
  • 日志格式的说明如下:
    • %h 为访问网站的IP
    • %l 为远程登陆名,这个字段基本上为”-“
    • %u 为用户名,当使用用户认证时,这个字段为认证的用户名
    • %t 为时间
    • %r 为请求的动作(比如用curel -I时就为HEADE)
    • %s 为请求的状态码,写成%>s为最后的状态码
    • %b 为传输数据大小
    • %{Referer}i 为referer信息(请求本次地址上一次的地址就为referer,比如在百度中搜索到该网站的地址,然后通过百度的搜索结果页面点击进入该网站,那这次请求的referer就是baidu,当然这个地址是很长的)
    • %{User-Agent}i 为浏览器标识,比如你用Firefox或者Chrome浏览器,则该字段显示内容不一样,是带有浏览器的标识的。
  • 对于这个日志格式,还可以自定义调整各个字段的位置,也可以额外增加其他字段,比如可以增加%D(请求耗费时间)
  • 在工作中一般不会去改它,默认的日志格式就够用了

然后继续编辑虚拟主机的配置文件,添加一行内容,即改成如下:

1
2
3
4
5
6
7
8
9
10
11
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.123.com$
RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L]
</IfModule>
CustomLog "logs/123.com-access_log" combined #<==就是添加这一行
</VirtualHost>

保存配置文件后,测试语法并重新加载配置:

1
2
3
4
5
6
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
[root@localhost ~]# curl -x127.0.0.1:80 -I 123.com
[root@localhost ~]# tail /usr/local/apache2.4/logs/123.com-access_log
127.0.0.1 - - [08/Mar/2018:04:51:07 +0800] "HEAD http://123.com/ HTTP/1.1" 301 - "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

发现生成了日志,并且有相关的日志记录。另外,用浏览器访问一下,再次查看日志,多了一行,如下所示:

1
192.168.1.2 - - [08/Mar/2018:04:52:54 +0800] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"


一个网站会有很多元素,尤其是图片、js、css等静态文件非常多,用户每请求一个页面就会访问诸多的图片、js等静态元素,这些元素的请求都会被记录到日志中。如果一个站点访问量很大,那么访问日志文件增长会非常快,一天可以达到几GB。这不仅对于服务器的磁盘空间造成影响,更重要的是会影响磁盘的读写速度。而且,访问日志很重要,又不能不去记录,这该怎么办呢?

好在这些巨量的静态元素请求记录到日志里意义并不大,所以可以限制这些静态元素去记录日志,并且需要把日志按天归档,一天一个日志,这样也可以防止单个日志文件过大。配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.123.com$
RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L]
</IfModule>
SetEnvIf Request_URI ".*\.gif$" image-request #<==主要是从这开始到下面的这些代码
SetEnvIf Request_URI ".*\.jpg$" image-request
SetEnvIf Request_URI ".*\.png$" image-request
SetEnvIf Request_URI ".*\.bmp$" image-request
SetEnvIf Request_URI ".*\.swf$" image-request
SetEnvIf Request_URI ".*\.js$" image-request
SetEnvIf Request_URI ".*\.css$" image-request
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined env=!image-request
</VirtualHost>

上面配置文件的说明:

  • 先定义了一个image-request环境变量,把gif、jpg、png、bmp、swf、js、css等格式的文件全部归类到image-request
  • 后面的env=!image-request有用到一个!,相当于取反,意思是把image-request以外的类型文件记录到日志里
  • 正常应该CustomLog后面为日志文件名,但在这里用了一个管道,它会把日志内容交给后面的rotatelogs命令处理。
  • 这个rotatelogs为httpd自带切割日志的工具,它会把访问日志按照我们定义的文件名格式进行切割,其中86400单位为秒,相当于一天。-l的作用是校准时区为UTC,也就是北京时间。

保存配置文件后,测试配置文件是否有错误,没有错误重新加载服务,然后测试看是否有我们自己定义的格式日志产生:

1
2
3
4
5
6
7
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
[root@localhost ~]# curl -x127.0.0.1:80 -I 123.com
[root@localhost ~]# ll /usr/local/apache2.4/logs/
-rw-r--r-- 1 root root 196 38 05:11 123.com-access_20180308.log
...

这里的123.com-access_20180308.log就是新生成的日志,而且以后每天生成一个按日期命名的日志。

接下来测试一下”在日志不记录静态元素”的配置:

1
2
3
4
5
6
7
[root@localhost ~]# touch /data/wwwroot/www.123.com/aming.jpg
[root@localhost ~]# touch /data/wwwroot/www.123.com/aming.txt
[root@localhost ~]# curl -x127.0.0.1:80 www.123.com/aming.jpg
[root@localhost ~]# curl -x127.0.0.1:80 www.123.com/aming.txt
[root@localhost ~]# cat /usr/local/apache2.4/logs/123.com-access_20180308.log
127.0.0.1 - - [08/Mar/2018:05:11:42 +0800] "HEAD http://123.com/ HTTP/1.1" 301 - "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
127.0.0.1 - - [08/Mar/2018:05:15:49 +0800] "GET http://www.123.com/aming.txt HTTP/1.1" 200 - "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

可以看到,123.com-access_20180308日志中只有aming.txt的请求日志,但没有aming.jpg的请求日志。这说明去除静态元素的记录日志配置成功了,这样一来,日志文件会瘦身很多。

当然,httpd的错误日志的切割也一样,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.123.com$
RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L]
</IfModule>
SetEnvIf Request_URI ".*\.gif$" image-request
SetEnvIf Request_URI ".*\.jpg$" image-request
SetEnvIf Request_URI ".*\.png$" image-request
SetEnvIf Request_URI ".*\.bmp$" image-request
SetEnvIf Request_URI ".*\.swf$" image-request
SetEnvIf Request_URI ".*\.js$" image-request
SetEnvIf Request_URI ".*\.css$" image-request
ErrorLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-error_%Y%m%d.log 86400" #<==这行是错误日志
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined env=!image-request
</VirtualHost>

说明:

  • 日志切割的是两行,注意不要写成多于两行。
  • ErrorLog是错误日志,CustomLog是访问日志。
  • 其实错误日志所记录的东西并不会太多,所以没有必要对错误日志进行分割。
  • 在Apache的log目录中,错误日志有两个,其中一个是apache总的错误日志,另外一个是针对虚拟主机的错误日志。
  • 可以把清除过期日志用计划任务的方式来实现,比如清除一个月前的日志,在每天某点某分执行这个操作。

5. 配置静态元素过期时间

有时,会在日志里发现有这样的状态码304,这个状态码表示该文件已经缓存在用户的电脑里了,再次请求它的时候就不用从服务器上下载,而是直接访问用户电脑里面的缓存。这样做的目的是降低服务器的资源消耗,还可以提升用户访问网站的速度。平时我们访问一个网站时,很多元素为静态的小图片,那这些小图片完全可以缓存在咱们的电脑里,这样再次访问该站点时,速度就会很快。

那到底能够缓存多久呢?如果服务器上的某个图片更新了,那么应该访问新的图片才对。这就涉及一个静态文件缓存时长的问题,也叫做缓存过期时间。在httpd的配置文件中,我们是可以控制这个时间的。

编辑虚拟主机配置文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@localhost ~]# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.123.com$
RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L]
</IfModule>
SetEnvIf Request_URI ".*\.gif$" image-request
SetEnvIf Request_URI ".*\.jpg$" image-request
SetEnvIf Request_URI ".*\.png$" image-request
SetEnvIf Request_URI ".*\.bmp$" image-request
SetEnvIf Request_URI ".*\.swf$" image-request
SetEnvIf Request_URI ".*\.js$" image-request
SetEnvIf Request_URI ".*\.css$" image-request
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined env=!image-request
<IfModule mod_expires.c> #<==添加从此行开始以及下面的内容
ExpiresActive on
ExpiresByType image/gif "access plus 1 days"
ExpiresByType image/jpeg "access plus 24 hours"
ExpiresByType image/png "access plus 24 hours"
ExpiresByType text/css "access plus 2 hours"
ExpiresByType application/x-javascript "now plus 2 hours"
ExpiresByType application/javascript "now plus 2 hours"
ExpiresByType application/x-shockwave-flash "now plus 2 hours"
ExpiresDefault "now plus 0 min"
</IfModule>
</VirtualHost>

这部分用到了mod_expires模块。这里gif、jpeg、png格式的文件过期时长为1天,css、js、flash格式文件过期时长为2小时,其它文件过期时长为0,也就是不缓存。保存配置文件,检查配置是否有问题,没问题重新加载服务:

1
2
3
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful

检查httpd是否加载expires模块:

1
2
3
4
5
6
7
8
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -M | grep -i expires
#<==没有任何输出,说明当前httpd并不支持expires模块,所以需要修改httpd主配置文件,打开该模块
[root@localhost ~]# vim /usr/local/apache2.4/conf/httpd.conf
#<==搜索expires关键词,找到下面的行,将前面的井号删除,保存退出
#LoadModule expires_module modules/mod_expires.so
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful #<==重新加载服务
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -M | grep -i expires
expires_module (shared) #<==有这行输出,说明已经正确加载expires模块

下面使用curl来测试它的效果:

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# curl -x127.0.0.1:80 -I www.123.com/aming.jpg
HTTP/1.1 200 OK
Date: Wed, 07 Mar 2018 22:12:16 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Last-Modified: Wed, 07 Mar 2018 21:14:46 GMT
ETag: "0-566d90c73d095"
Accept-Ranges: bytes
Cache-Control: max-age=86400
Expires: Thu, 08 Mar 2018 22:12:16 GMT
Content-Type: image/jpeg

可以看到max-age=86400,这说明jpg的图片将缓存86400秒,也就是一天。而这里的状态码为200而不是304,这是因为测试工具是curl,没有缓存功能。再测试一下txt文件:

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# curl -x127.0.0.1:80 -I www.123.com/aming.txt
HTTP/1.1 200 OK
Date: Wed, 07 Mar 2018 22:13:59 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Last-Modified: Wed, 07 Mar 2018 21:14:49 GMT
ETag: "0-566d90ca252d5"
Accept-Ranges: bytes
Cache-Control: max-age=0
Expires: Wed, 07 Mar 2018 22:13:59 GMT
Content-Type: text/plain

其中max-age=0,说明没有缓存该类型的文件。


6. 配置防盗链

配置防盗链非常的重要,这也是在工作中经常会做的工作。

防盗链,通俗讲,就是不让别人盗用你网站上上的资源,这个资源,通常指的是图片、视频、歌曲、文档等。讲解防盗链配置之前,先了解一下referer的概念,上面在讲解日志格式的时候也提到过它。当你通过A网站的一个页面里面的连接去访问B网站的一个页面时,那么这个B网站页面的referer就是A网站的页面地址。

接下来配置防盗链的过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@localhost ~]# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
#<==编辑虚拟机配置文件,为了方便查看特定的重要设置,已经把前面所进行的实验功能删去。
#<==新添加的内容如下”
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined env=!image-request
<Directory /data/wwwroot/www.123.com> #<==从这开始配置防盗链的功能的
SetEnvIfNoCase Referer "http://www.123.com" local_ref
SetEnvIfNoCase Referer "http://123.com" local_ref
SetEnvIfNoCase Referer "^$" local_ref
<filesmatch "\.(txt|doc|mp3|zip|rar|jpg|gif)">
Order Allow,Deny
Allow from env=local_ref
</filesmatch>
</Directory>
</VirtualHost>

上面配置内容的说明:

  • 首先定义允许访问链接的referer,其中^$为空referer,当直接在浏览器里输入图片地址去访问它时,它的referer就为空。
  • 然后又使用filesmatch来定义需要保护的文件类型,访问txt、doc、mp3、zip、rar、jpg、gif格式的文件,当访问这样类型的文件时就会被限制。

下面是测试过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
[root@localhost ~]# curl -x127.0.0.1:80 -I -e "http://www.123.com/123.txt" http://www.123.com/aming.jpg
HTTP/1.1 200 OK
Date: Wed, 07 Mar 2018 22:33:45 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Last-Modified: Wed, 07 Mar 2018 21:14:46 GMT
ETag: "0-566d90c73d095"
Accept-Ranges: bytes
Content-Type: image/jpeg
#<==使用-e来定义referer,这个referer一定要以http://开头,否则不管用
[root@localhost ~]# curl -x127.0.0.1:80 -I -e "http://www.1234.com/1.txt" http://www.123.com/aming.jpg
HTTP/1.1 403 Forbidden
Date: Wed, 07 Mar 2018 22:34:54 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Content-Type: text/html; charset=iso-8859-1
#<==使用非允许的referer会返回403的状态码
[root@localhost ~]# curl -x127.0.0.1:80 -I -e "http://www.1234.com/1.txt" http://www.123.com/index.html
HTTP/1.1 200 OK
Date: Wed, 07 Mar 2018 22:35:07 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Last-Modified: Wed, 07 Mar 2018 17:20:54 GMT
ETag: "8-566d5c8150174"
Accept-Ranges: bytes
Content-Length: 8
Content-Type: text/html
#<==访问HTML类型的文件时,也不会被保护


7. 访问控制

对于一些比较重要的网站内容,除了可以使用用户认证限制访问之外,还可以通过其他一些方法做到限制,比如可以限制IP,也可以限制user_agent。限制IP指的是限制访问网站的来源IP,而限制user_agent,通常用来限制恶意或者不正常的请求。

有的公司使用httpd,会对安全要求非常严格,凡是涉及后台的访问都要做IP限制,只允许公司内网IP或者被信任的公网IP访问。这样做的目的是为了防止别有用心的人拿到后台权限,并获得内部数据。

先来看如何限制IP访问,编辑虚拟机配置文件,改成如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost ~]# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com 456.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<Directory /data/wwwroot/www.123.com/admin> #<==就是配置这里
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Directory>
</VirtualHost>

上述配置文件的说明:

  • 使用<Directory>来指定要限制访问的目录
  • Order定义控制顺序,哪个在前面就先匹配哪个规则。在本例中deny在前,所以先匹配Deny from all,这样所有的来源IP都会被限制,然后匹配Allow from 127.0.0.1,这样又允许了127.0.0.1这个IP。
  • 最终的效果就是,只允许来源IP为127.0.0.1的访问。

下面是验证过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost ~]# mkdir /data/wwwroot/www.123.com/admin/
[root@localhost ~]# echo "admin" > /data/wwwroot/www.123.com/admin/index.html
[root@localhost ~]# > /usr/local/apache2.4/logs/123.com-access_20180309.log
[root@localhost ~]# curl -x192.168.1.111:80 -I www.123.com/admin/index.html
HTTP/1.1 403 Forbidden
Date: Thu, 08 Mar 2018 18:33:52 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Content-Type: text/html; charset=iso-8859-1
[root@localhost ~]# curl -x127.0.0.1:80 -I www.123.com/admin/index.html
HTTP/1.1 200 OK
Date: Thu, 08 Mar 2018 18:34:05 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Last-Modified: Thu, 08 Mar 2018 18:24:51 GMT
ETag: "6-566eaca9c8e06"
Accept-Ranges: bytes
Content-Length: 6
Content-Type: text/html
[root@localhost ~]# cat /usr/local/apache2.4/logs/123.com-access_20180309.log
192.168.1.111 - - [09/Mar/2018:02:33:52 +0800] "HEAD http://www.123.com/admin/index.html HTTP/1.1" 403 - "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
127.0.0.1 - - [09/Mar/2018:02:34:05 +0800] "HEAD http://www.123.com/admin/index.html HTTP/1.1" 200 - "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

在上例中,本机有两个IP,一个是192.168.1.111,另一个是127.0.0.1,通过这两个IP都可以访问到站点。而来源IP分别为192.168.1.111和127.0.0.1,其实和本机IP是一样的。可以看到,我们所配置的功能已经实现了:用192.168.1.111访问的状态是403,表示没有权限;用127.0.0.1访问的状态是200,表示成功访问。

再来用浏览器测试一下,测试完成后查看一下httpd的访问日志:

1
2
[root@localhost ~]# tail -1 /usr/local/apache2.4/logs/123.com-access_20180309.log
192.168.1.2 - - [09/Mar/2018:02:39:34 +0800] "GET /admin/index.html HTTP/1.1" 403 225 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"

也可以单独针对某个文件来做限制,编辑虚拟机配置文件,修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~]# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<Directory /data/wwwroot/www.123.com> #<==就是配置这里
<Filesmatch "admin.php(.*)">
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Filesmatch>
</Directory>
</VirtualHost>


8. 禁止解析PHP

对于使用PHP语言编写的网站,有一些目录是有需求上传文件的。如果网站的代码有漏洞,让一些别有用心的人上传了一个用PHP代码写的木马,由于网站可以执行PHP程序,最终会让别人拿到服务器的权限。为了避免这种情况发生,我们需要把能上传文件的目录直接禁止解析PHP代码(不用担心会影响网站的访问,若是这种目录也需要解析PHP,那说明程序员不合格)。

配置如下:

1
2
3
4
5
6
7
8
9
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<Directory /data/wwwroot/www.123.com/upload> #<==就是配置这里
php_admin_flag engine off
</Directory>
</VirtualHost>

验证过程如下:

1
2
3
4
5
6
7
8
9
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
[root@localhost ~]# mkdir /data/wwwroot/www.123.com/upload/
[root@localhost ~]# cp /usr/local/apache2.4/htdocs/1.php /data/wwwroot/www.123.com/upload/
[root@localhost ~]# curl -x127.0.0.1:80 www.123.com/upload/1.php
<?php
echo "PHP解析正常!"
?>

显示了PHP的源代码,这说明PHP没有被正常解析。


9. 禁止指定的user_agent访问

user_agent是浏览器标识,当用curl访问时user_agent为"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2",当用Chrome浏览器访问时user_agent为"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"

通常在工作中会对user_agent做一些访问,比如可以限制一些不太友好的搜索引擎爬虫。你之所以能在百度上面搜到某个网站,是因为百度会派一些蜘蛛爬虫来抓取网站的数据。蜘蛛爬虫抓取数据类似于用户用浏览器访问网站,当蜘蛛爬虫太多或者访问太频繁,就会浪费服务器的资源。另外,也可以限制恶意请求,这种恶意请求我们通常称作cc攻击,它的原理很简单,就是用很多用户的电脑同时访问同一个站点,当访问量或者频率达到一定层次,会耗尽服务器资源,从而使之不能正常提供服务。这种cc攻击其实有很明显的规律,其中这些恶意请求的user_agent相同或者相似,那么我们就可以通过限制user_agent发挥防攻击的作用。

下面是针对user_agent来做访问控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~]# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<IfModule mod_rewrite.c> #<==从这里开始配置
RewriteEngine On
RewriteEngine %{HTTP_USER_AGENT} .*curl.* [NC,OR]
RewriteEngine %{HTTP_USER_AGENT} .*baidu.com.*
[NC]
RewriteEngine .* - [F]
</IfModule>
</VirtualHost>

上述配置的说明:

  • 这个需求也用到了rewrite模块
  • %{HTTP_USER_AGENT}为user_agent的内置变量
  • 在本例中当user_agent匹配usrl或者baidu.com时,都会触发下面的规则。
  • 方括号中的OR表示或者,NC表示不区分大小写,F表示Forbidden。

验证过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl -t
Syntax OK
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
[root@localhost ~]# curl -I -x127.0.0.1:80 www.123.com/upload/1.php
HTTP/1.1 403 Forbidden
Date: Thu, 08 Mar 2018 19:17:34 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
Content-Type: text/html; charset=iso-8859-1
[root@localhost ~]# curl -A "123123" -I -x127.0.0.1:80 www.123.com/upload/1.php
HTTP/1.1 200 OK
Date: Thu, 08 Mar 2018 19:18:59 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
X-Powered-By: PHP/5.6.34
Content-Type: text/html; charset=UTF-8

curl的-A选项指定user_agent。第一个请求,user_agent为”usrl…”的,匹配了第一个条件,所以会403.第二个请求,user_agent为自定义的”123123”,没有匹配任何条件,所以状态码为200。


10. Apache通过rewrite限制某个目录

我们可以用allow和deny去限制网站根目录下的某个子目录,当然,利用rewrite也可以实现,配置如下:

1
2
3
4
5
6
7
8
9
10
11
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
<IfModule mod_rewrite.c> #<==从这里开始配置
RewriteEngine on
RewriteCond %{REQUEST_URI} ^.*/tmp/.* [NC]
RewriteRule .* - [F]
</IfModule>
</VirtualHost>

这段配置,会把只要包含/tmp/字样的请求都限制了。

0%